package msu.ml.presentation;

import msu.ml.data.level2.*;
import weka.core.*;
import java.util.*;
import java.io.*;
import javax.imageio.*;
import java.awt.image.*;
import java.awt.*;

public class ScanRenderer
{
	private static Color [] palette = {
      new Color(0x324F4F), 
      new Color(0x00ECEC), 
      new Color(0x01A0F6), 
		new Color(0x0000F6), 
      new Color(0x00FF00),
      new Color(0x00C800),
      new Color(0x009000), 
		new Color(0xFFFF00), 
      new Color(0xE7C000),
      new Color(0xFF9000),
      new Color(0xFF0000),
      new Color(0xD60000),
      new Color(0xC00000)};

	private static Color [] palette2 = {
      new Color(0xFF0000),
      new Color(0x00FF00), 
      new Color(0x0000FF), 
		new Color(0xFFFF00), 
      new Color(0x00FFFF),
      new Color(0xFF00FF),
      new Color(0x222222), 
		new Color(0x555555), 
      new Color(0x888888),
      new Color(0xBBBBBB),
      new Color(0xEEEEEE),
      new Color(0xD60000),
      new Color(0xC00000)};
   
   public static void saveWindow(double [][] data, String file, 
      int width, int height)
   {
      try
      {
         BufferedImage image = new BufferedImage(width, 
               height, BufferedImage.TYPE_INT_ARGB);
         Graphics2D g = image.createGraphics();
         g.setColor(Color.white);
         g.fillRect(0,0,width,height);

         int cellWidth = width / data.length;
         int cellHeight = height / data.length;

         for(int j = 0; j < data.length; j++)
         {
            for(int i = 0; i < data.length; i++)
            {
               if(data[j][i] == Ray.EMPTY)
               {
                  g.setColor(Color.white);
               }
               else
               {
                  float grad = 1.0f - (float)((data[j][i] + 32.0) / 126.5);
                  g.setColor(new Color(grad, grad, grad));
               }

               g.fillRect(j * cellWidth, height - ((i+1) * cellHeight), 
                  cellWidth, cellHeight);
            }
         }
      
         File imageFile = new File(file);
         ImageIO.write(image, "png", imageFile);
      }
      catch(Exception e)
      {
         System.out.println("Exception while saving image");
         System.out.println(e.getMessage());
         e.printStackTrace();
      }
   }
	
   public static BufferedImage getImage(Instances data, int [] clusters, int width, int height)
   {
      try
      {
         int [] x = new int[clusters.length];
         int [] y = new int[clusters.length];

         BufferedImage image = new BufferedImage(width, 
               height, BufferedImage.TYPE_INT_ARGB);
         Graphics2D g = image.createGraphics();
         g.setColor(Color.white);
         g.fillRect(0,0,width,height);
         for(int i = 0; i < data.numInstances(); i++)
         {
            Instance inst = data.instance(i);
            x[i] = (int)inst.value(0) + (width / 2);
            y[i] = height - ((int)inst.value(1) + (height / 2));
         }

         for(int i = 0; i < x.length; i++)
         {
            if(clusters[i] >= 0)
            {
               g.setColor(ScanRenderer.palette2[clusters[i] % 
                     ScanRenderer.palette2.length]);
               g.fillOval(x[i], y[i], 2, 2);
            }
         }
         
         return image;
      }
      catch(Exception e)
      {
         System.out.println("Exception rendering saving image");
         System.out.println(e.getMessage());
         e.printStackTrace();
      }

      return null;
   }

   public static void saveImage(Instances data, int [] clusters, String file, 
      int width, int height)
   {
      try
      {
         int [] x = new int[clusters.length];
         int [] y = new int[clusters.length];

         BufferedImage image = new BufferedImage(width, 
               height, BufferedImage.TYPE_INT_ARGB);
         Graphics2D g = image.createGraphics();
         g.setColor(Color.white);
         g.fillRect(0,0,width,height);
         for(int i = 0; i < data.numInstances(); i++)
         {
            Instance inst = data.instance(i);
            x[i] = (int)inst.value(0) + (width / 2);
            y[i] = height - ((int)inst.value(1) + (height / 2));
         }

         for(int i = 0; i < x.length; i++)
         {
            if(clusters[i] >= 0)
            {
               g.setColor(ScanRenderer.palette2[clusters[i] % 
                     ScanRenderer.palette2.length]);
               g.fillOval(x[i], y[i], 2, 2);
            }
         }

         File imageFile = new File(file);
         ImageIO.write(image, "png", imageFile);
      }
      catch(Exception e)
      {
         System.out.println("Exception while saving image");
         System.out.println(e.getMessage());
         e.printStackTrace();
      }


   }

   public static void saveErrorScan(Scan scan, String file, int width, 
      int height, int targetRange, double targetAz)
   {
      try
      {
         BufferedImage image = new BufferedImage(width, 
               height, BufferedImage.TYPE_INT_ARGB);
         Graphics2D g = image.createGraphics();
         g.setColor(Color.white);
         g.fillRect(0,0,width,height);

         for(int j = 0; j < scan.numRays(); j++)
         {
            Ray ray = scan.getRay(j);
            double [] data = ray.getReflectivityData();

            for(int i = 0; i < data.length; i++)
            {
               if(data[i] == Ray.EMPTY)
                  continue;

               double r = i;
               double dt = .95;
               double t = azimuthToTheta(ray.getAzimuth());

               int [] x = {cX(r, t), cX(r + 1, t), cX(r + 1, t - dt), cX(r, t - dt)};
               int [] y = {cY(r, t), cY(r + 1, t), cY(r + 1, t - dt), cY(r, t - dt)};

               translate(x, width / 2);
               translate(y, height / 2);
               for(int k = 0; k < y.length; k++)
                  y[k] = height - y[k];

               int colorIndex = (int)(((data[i] + 32.0) / 126.5) 
                  * (double)ScanRenderer.palette.length);
               colorIndex = Math.min(colorIndex, ScanRenderer.palette.length - 1);
               g.setColor(ScanRenderer.palette[colorIndex]);

               g.fillPolygon(x, y, 4);
            }
         }

         int rangeIndex = scan.getRay(0).getReflectivityRangeIndex(targetRange);
         double targetTheta = azimuthToTheta(targetAz);
         int x = (cX(rangeIndex, targetTheta) + (width / 2));
         int y = height - (cY(rangeIndex, targetTheta) + (width / 2));

         g.setColor(Color.red);
         g.drawOval(x - 2, y - 2, 4, 4);

         File imageFile = new File(file);
         ImageIO.write(image, "png", imageFile);
      }
      catch(Exception e)
      {
         System.out.println(e);
         e.printStackTrace();
      }
      
   }

   public static BufferedImage getImage(Scan scan, IRayDataProvider provider, int width, int height)
   {
      try
      {
         BufferedImage image = new BufferedImage(width, 
               height, BufferedImage.TYPE_INT_ARGB);
         Graphics2D g = image.createGraphics();
         g.setColor(Color.white);
         g.fillRect(0,0,width,height);

         double minData = Double.MAX_VALUE;
         double maxData = Double.MIN_VALUE;
         for(int j = 0; j < scan.numRays(); j++)
         {
            Ray ray = scan.getRay(j);
            double [] data = provider.createForRay(ray).getData();
            for(int i = 0; i < data.length; i++)
               if(data[i] != Ray.EMPTY && data[i] < minData)
                  minData = data[i];
            for(int i = 0; i < data.length; i++)
               if(data[i] != Ray.EMPTY && data[i] > maxData)
                  maxData = data[i];
         }

         for(int j = 0; j < scan.numRays(); j++)
         {
            Ray ray = scan.getRay(j);
            double [] data = provider.createForRay(ray).getData();

            for(int i = 0; i < data.length; i++)
            {
               if(data[i] == Ray.EMPTY)
                  continue;

               double r = i;
               double dt = .95;
               double t = ray.getAzimuth() - 90;
               if(t < 0)
                  t += 360;
               if(t != 0)
                  t = 360 - t;


               int [] x = {cX(r, t), cX(r + 1, t), cX(r + 1, t - dt), cX(r, t - dt)};
               int [] y = {cY(r, t), cY(r + 1, t), cY(r + 1, t - dt), cY(r, t - dt)};

               translate(x, width / 2);
               translate(y, height / 2);
               for(int k = 0; k < y.length; k++)
                  y[k] = height - y[k];

               int colorIndex = (int)(((data[i] - minData) / (maxData - minData)) 
                  * (float)ScanRenderer.palette.length);
               colorIndex = Math.min(colorIndex, ScanRenderer.palette.length - 1);
               g.setColor(ScanRenderer.palette[colorIndex]);

               g.fillPolygon(x, y, 4);
            }
         }

         return image;
      }
      catch(Exception e)
      {
         System.out.println(e);
         e.printStackTrace();
      }
      return null;
   }

   public static void saveImage(Scan scan, IRayDataProvider provider, String file, int width, int height)
   {
      try
      {
         BufferedImage image = new BufferedImage(width, 
               height, BufferedImage.TYPE_INT_ARGB);
         Graphics2D g = image.createGraphics();
         g.setColor(Color.white);
         g.fillRect(0,0,width,height);

         double minData = Double.MAX_VALUE;
         double maxData = Double.MIN_VALUE;
         for(int j = 0; j < scan.numRays(); j++)
         {
            Ray ray = scan.getRay(j);
            double [] data = provider.createForRay(ray).getData();
            for(int i = 0; i < data.length; i++)
               if(data[i] != Ray.EMPTY && data[i] < minData)
                  minData = data[i];
            for(int i = 0; i < data.length; i++)
               if(data[i] != Ray.EMPTY && data[i] > maxData)
                  maxData = data[i];
         }

         for(int j = 0; j < scan.numRays(); j++)
         {
            Ray ray = scan.getRay(j);
            double [] data = provider.createForRay(ray).getData();

            for(int i = 0; i < data.length; i++)
            {
               if(data[i] == Ray.EMPTY)
                  continue;

               double r = i;
               double dt = .95;
               double t = azimuthToTheta(ray.getAzimuth());


               int [] x = {cX(r, t), cX(r + 1, t), cX(r + 1, t - dt), cX(r, t - dt)};
               int [] y = {cY(r, t), cY(r + 1, t), cY(r + 1, t - dt), cY(r, t - dt)};

               translate(x, width / 2);
               translate(y, height / 2);
               for(int k = 0; k < y.length; k++)
                  y[k] = height - y[k];

               int colorIndex = (int)(((data[i] - minData) / (maxData - minData)) 
                  * (double)ScanRenderer.palette.length);
               colorIndex = Math.min(colorIndex, ScanRenderer.palette.length - 1);
               g.setColor(ScanRenderer.palette[colorIndex]);

               g.fillPolygon(x, y, 4);
            }
         }

         File imageFile = new File(file);
         ImageIO.write(image, "png", imageFile);
      }
      catch(Exception e)
      {
         System.out.println(e);
         e.printStackTrace();
      }
   }

   private static double azimuthToTheta(double az)
   {
      double t = az - 90;
      if(t < 0)
         t += 360;
      if(t != 0)
         t = 360 - t;
      return t;
   }

   private static void translate(int [] values, int dx)
   {
      for(int i = 0; i < values.length; i++)
         values[i] += dx;
   }

   private static int cX(double r, double theta)
   {
      //return (int)(r * 2.0 * Math.cos(theta * Math.PI / 180.0));
      return (int)(r * Math.cos(theta * Math.PI / 180.0));
   }

   private static int cY(double r, double theta)
   {
      //return (int)(r * 2.0 * Math.sin(theta * Math.PI / 180.0));
      return (int)(r * Math.sin(theta * Math.PI / 180.0));
   }
}
